using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Text;

namespace OracleInternal.Common
{
	internal class TimeZoneFileReader
	{
		internal struct LTZMeta
		{
			internal int ntrans_ltzmeta;

			internal int trans_ltzmeta;

			internal int name_ltzmeta;

			internal int primary_id_ltzmeta;
		}

		internal class LTZHead
		{
			internal int magic_ltzhead;

			internal int size_ltzhead;

			internal short version_ltzhead;

			internal short contver_ltzhead;

			internal short tzfileid_ltzhead;

			internal short nid_ltzhead;

			internal int ntrans_ltzhead;

			internal int ntag_ltzhead;

			internal int nidoff_ltzhead;

			internal int transoff_ltzhead;

			internal int tagoff_ltzhead;

			internal int tagmapoff_ltzhead;

			internal int dstoff_ltzhead;

			internal LTZMeta[] meta_ltzhead = new LTZMeta[8192];

			internal int cstveroff_ltzhead;

			internal int[] dummy_ltzhead = new int[3];
		}

		internal struct LdiDateTime
		{
			internal short year_LdiDateTime;

			internal byte month_LdiDateTime;

			internal byte day_LdiDateTime;

			internal byte hour_LdiDateTime;

			internal byte minute_LdiDateTime;

			internal byte second_LdiDateTime;

			internal uint fracsec_LdiDateTime;

			internal sbyte tzhour_LdiDateTime;

			internal sbyte tzminute_LdiDateTime;

			internal byte type_LdiDateTime;

			internal ushort regid_LdiDateTime;
		}

		internal struct LTZtag
		{
			internal int gmtoff_ltztag;

			internal uint label_ltztag;
		}

		private const int LTZ_MINSPERHOUR = 60;

		private const int LTZ_SECSPERMIN = 60;

		private const int LTZ_HOURSPERDAY = 24;

		private const int LTZ_SECSPERHOUR = 3600;

		private const int LTZERR_OK = 0;

		private const int LTZERR_NULL_PTR = 1;

		private const int LTZERR_BAD_DATA = 2;

		private const int LTZERR_BAD_VER = 3;

		private const int LTZERR_INV_ZONE = 4;

		private const int LTZERR_NO_DATA = 5;

		private const int LTZERR_BAD_ABBRV = 6;

		private const int LTZERR_INV_DATE = 7;

		private const int LTZERR_BAD_MEM = 8;

		private const int LTZ_NUM_IDS = 8192;

		private const int LTZ_REGID_BITS = 13;

		private const int LTZ_MAGIC = 1332892762;

		private const short LTZ_VERSION = 3;

		private const int LTZ_MAX_FILE_SIZE = 2097152;

		internal OracleTimeZone ReadObj()
		{
			int latestTZVersion = 0;
			string name = "";
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				if (text.StartsWith("Oracle.ManagedDataAccess.OracleInternal.I18N.TimeZone", StringComparison.InvariantCultureIgnoreCase) && text.EndsWith(".dst", StringComparison.InvariantCultureIgnoreCase))
				{
					latestTZVersion = Convert.ToInt32(text.Split('_', '.')[5]);
					name = text;
					break;
				}
			}
			using GZipStream gZipStream = new GZipStream(executingAssembly.GetManifestResourceStream(name), CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			gZipStream.CopyTo(memoryStream);
			memoryStream.Position = 0L;
			BinaryReader binaryReader = new BinaryReader(memoryStream);
			LTZHead lTZHead = new LTZHead();
			int errcode = -1;
			lTZHead = PopulateHead(binaryReader, out errcode);
			if (errcode != 0)
			{
				throw new Exception("Errorcode not present, Error in populating the head");
			}
			LdiDateTime[] dttab = ReadTransitionsOfAllZones(lTZHead, binaryReader);
			LTZtag[] tagtab = PopulateTagArray(lTZHead, binaryReader);
			short[] tagmap = PopulateTagMapArray(lTZHead, binaryReader);
			byte[] dstflag = PopulateDSTFlagArray(lTZHead, binaryReader);
			Dictionary<int, string> zoneIdMap = PopulateZoneIdMapHashtable(lTZHead, binaryReader);
			Hashtable zoneIdtoOffsetMap = PopulateZoneOffsetMapHashtable(lTZHead, dttab, tagmap, tagtab, dstflag);
			OracleTimeZone oracleTimeZone = new OracleTimeZone();
			oracleTimeZone.SetZoneIdMap(zoneIdMap);
			oracleTimeZone.SetZoneIdtoOffsetMap(zoneIdtoOffsetMap);
			oracleTimeZone.SetLatestTZVersion(latestTZVersion);
			binaryReader.Close();
			return oracleTimeZone;
		}

		internal LTZHead PopulateHead(BinaryReader binaryReader, out int errcode)
		{
			LTZHead lTZHead = new LTZHead();
			lTZHead.magic_ltzhead = binaryReader.ReadInt32();
			lTZHead.size_ltzhead = binaryReader.ReadInt32();
			lTZHead.version_ltzhead = binaryReader.ReadInt16();
			lTZHead.contver_ltzhead = binaryReader.ReadInt16();
			lTZHead.tzfileid_ltzhead = binaryReader.ReadInt16();
			lTZHead.nid_ltzhead = binaryReader.ReadInt16();
			lTZHead.ntrans_ltzhead = binaryReader.ReadInt32();
			lTZHead.ntag_ltzhead = binaryReader.ReadInt32();
			lTZHead.nidoff_ltzhead = binaryReader.ReadInt32();
			lTZHead.transoff_ltzhead = binaryReader.ReadInt32();
			lTZHead.tagoff_ltzhead = binaryReader.ReadInt32();
			lTZHead.tagmapoff_ltzhead = binaryReader.ReadInt32();
			lTZHead.dstoff_ltzhead = binaryReader.ReadInt32();
			int num = 0;
			if (lTZHead.magic_ltzhead != 1332892762)
			{
				num = 2;
			}
			else if (lTZHead.version_ltzhead != 3)
			{
				num = 3;
			}
			else if (lTZHead.size_ltzhead > 2097152)
			{
				num = 2;
			}
			errcode = num;
			if (errcode == 0)
			{
				for (int i = 0; i < 8192; i++)
				{
					lTZHead.meta_ltzhead[i] = default(LTZMeta);
				}
				for (int j = 0; j < 8192; j++)
				{
					lTZHead.meta_ltzhead[j].ntrans_ltzmeta = binaryReader.ReadInt32();
					lTZHead.meta_ltzhead[j].trans_ltzmeta = binaryReader.ReadInt32();
					lTZHead.meta_ltzhead[j].name_ltzmeta = binaryReader.ReadInt32();
					lTZHead.meta_ltzhead[j].primary_id_ltzmeta = binaryReader.ReadInt32();
				}
				lTZHead.cstveroff_ltzhead = binaryReader.ReadInt32();
				lTZHead.dummy_ltzhead[0] = binaryReader.ReadInt32();
				lTZHead.dummy_ltzhead[1] = binaryReader.ReadInt32();
				lTZHead.dummy_ltzhead[2] = binaryReader.ReadInt32();
			}
			return lTZHead;
		}

		internal LdiDateTime[] ReadTransitionsOfAllZones(LTZHead head, BinaryReader binaryReader)
		{
			binaryReader.BaseStream.Seek(head.transoff_ltzhead, SeekOrigin.Begin);
			LdiDateTime[] array = new LdiDateTime[head.ntrans_ltzhead];
			for (int i = 0; i < head.ntrans_ltzhead; i++)
			{
				array[i] = default(LdiDateTime);
				array[i].year_LdiDateTime = binaryReader.ReadInt16();
				array[i].month_LdiDateTime = binaryReader.ReadByte();
				array[i].day_LdiDateTime = binaryReader.ReadByte();
				array[i].hour_LdiDateTime = binaryReader.ReadByte();
				array[i].minute_LdiDateTime = binaryReader.ReadByte();
				array[i].second_LdiDateTime = binaryReader.ReadByte();
				array[i].fracsec_LdiDateTime = binaryReader.ReadUInt32();
				array[i].tzhour_LdiDateTime = binaryReader.ReadSByte();
				array[i].tzminute_LdiDateTime = binaryReader.ReadSByte();
				array[i].type_LdiDateTime = binaryReader.ReadByte();
				array[i].regid_LdiDateTime = binaryReader.ReadUInt16();
				if (array[i].hour_LdiDateTime == 24)
				{
					array[i].day_LdiDateTime = (byte)(array[i].day_LdiDateTime + 1);
					array[i].hour_LdiDateTime = 0;
				}
				binaryReader.ReadInt32();
			}
			return array;
		}

		internal LTZtag[] PopulateTagArray(LTZHead head, BinaryReader binaryReader)
		{
			binaryReader.BaseStream.Seek(head.tagoff_ltzhead, SeekOrigin.Begin);
			LTZtag[] array = new LTZtag[head.ntag_ltzhead];
			for (int i = 0; i < head.ntag_ltzhead; i++)
			{
				array[i] = default(LTZtag);
				array[i].gmtoff_ltztag = binaryReader.ReadInt32();
				array[i].label_ltztag = binaryReader.ReadUInt32();
			}
			return array;
		}

		internal short[] PopulateTagMapArray(LTZHead head, BinaryReader binaryReader)
		{
			short[] array = new short[head.ntrans_ltzhead];
			binaryReader.BaseStream.Seek(head.tagmapoff_ltzhead, SeekOrigin.Begin);
			for (int i = 0; i < head.ntrans_ltzhead; i++)
			{
				array[i] = binaryReader.ReadInt16();
			}
			return array;
		}

		internal byte[] PopulateDSTFlagArray(LTZHead head, BinaryReader binaryReader)
		{
			byte[] array = new byte[head.ntrans_ltzhead];
			binaryReader.BaseStream.Seek(head.dstoff_ltzhead, SeekOrigin.Begin);
			for (int i = 0; i < head.ntrans_ltzhead; i++)
			{
				array[i] = binaryReader.ReadByte();
			}
			return array;
		}

		internal Dictionary<int, string> PopulateZoneIdMapHashtable(LTZHead head, BinaryReader binaryReader)
		{
			int nid_ltzhead = head.nid_ltzhead;
			int nidoff_ltzhead = head.nidoff_ltzhead;
			Dictionary<int, string> dictionary = new Dictionary<int, string>();
			for (int i = 0; i < nid_ltzhead; i++)
			{
				binaryReader.BaseStream.Seek(nidoff_ltzhead + 8 * i, SeekOrigin.Begin);
				int num = binaryReader.ReadInt32();
				int key = binaryReader.ReadInt32();
				binaryReader.BaseStream.Seek(num, SeekOrigin.Begin);
				StringBuilder stringBuilder = new StringBuilder();
				for (char c = binaryReader.ReadChar(); c != 0; c = binaryReader.ReadChar())
				{
					stringBuilder.Append(c);
				}
				string value = stringBuilder.ToString();
				if (!dictionary.ContainsKey(key))
				{
					dictionary.Add(key, value);
				}
			}
			return dictionary;
		}

		internal Hashtable PopulateZoneOffsetMapHashtable(LTZHead head, LdiDateTime[] dttab, short[] tagmap, LTZtag[] tagtab, byte[] dstflag)
		{
			Hashtable hashtable = new Hashtable();
			for (int i = 0; i < 8192; i++)
			{
				ZoneValue zoneValue = default(ZoneValue);
				LTZMeta lTZMeta = head.meta_ltzhead[i];
				uint ntrans_ltzmeta;
				if ((ntrans_ltzmeta = (uint)lTZMeta.ntrans_ltzmeta) == 0)
				{
					continue;
				}
				zoneValue.m_transitions = new Transitions[ntrans_ltzmeta];
				int num = 0;
				for (int j = 0; j < ntrans_ltzmeta; j++)
				{
					int num2 = lTZMeta.trans_ltzmeta + j;
					LdiDateTime ldiDateTime = dttab[num2];
					short num3 = tagmap[num2];
					LTZtag lTZtag = tagtab[num3];
					zoneValue.m_transitions[j] = default(Transitions);
					zoneValue.m_transitions[j].m_dateTimeInUtc = new DateTime(ldiDateTime.year_LdiDateTime, ldiDateTime.month_LdiDateTime, ldiDateTime.day_LdiDateTime, ldiDateTime.hour_LdiDateTime, ldiDateTime.minute_LdiDateTime, ldiDateTime.second_LdiDateTime);
					zoneValue.m_transitions[j].m_hourOffset = GetTimeSpan(lTZtag.gmtoff_ltztag);
					zoneValue.m_transitions[j].m_dst = dstflag[num2];
					zoneValue.m_transitions[j].m_dateTimeInLocal = zoneValue.m_transitions[j].m_dateTimeInUtc.Add(zoneValue.m_transitions[j].m_hourOffset);
					int num4 = lTZtag.gmtoff_ltztag - num;
					if (num4 < 0)
					{
						num4 = -num4;
					}
					zoneValue.m_transitions[j].m_dstDuration = GetTimeSpan(num4);
					if (zoneValue.m_transitions[j].m_dst != 0)
					{
						zoneValue.m_transitions[j].m_dateTimeInLocal = zoneValue.m_transitions[j].m_dateTimeInLocal.Add(GetTimeSpan(-num4));
					}
					num = lTZtag.gmtoff_ltztag;
				}
				hashtable.Add(i, zoneValue);
			}
			return hashtable;
		}

		private TimeSpan GetTimeSpan(int hourMinuteSecond)
		{
			int hours = hourMinuteSecond / 3600;
			hourMinuteSecond %= 3600;
			int minutes = hourMinuteSecond / 60;
			int seconds = hourMinuteSecond % 60;
			return new TimeSpan(hours, minutes, seconds);
		}
	}
}
